/** @file gui_widget.h
    @brief A general widget */

#ifndef G3_GUI_WIDGET_H
#define G3_GUI_WIDGET_H

#include "log.h"
#include "input.h"

#include "res/res_font.h"

#include "gui/gui_typemgr.h"

#include <vector>
#include <string>

namespace G3 {
namespace GUI {

/** @class WIDGET
    @brief A general widget class */
class WIDGET {
	public:
        /**
            @brief A constructor
        */
		WIDGET ();
        /**
            @brief A destructor
        */
		virtual ~WIDGET ();

        /** A widget state  */
		enum WIDGET_STATE {
		    /** The widget's up */
            W_UP = 0,
            /** Mouse is levitating over it */
            W_OVER = 1,
            /** A mouse sits on the widget */
            W_DOWN = 2
        };

        /** A notify event type */
		typedef boost::signal2<void, G3::INPUT *, WIDGET *> SIG_NOTIFY_EVENT;
		/** A signal connection type */
		typedef boost::signals::connection SIG_CONNECTION;
        /** A notification handler callback function pointer */
		typedef void (*NOTIFY_HANDLER)(G3::INPUT *, WIDGET *);

        /** Signal for Mouse-Over event */
		SIG_NOTIFY_EVENT SigMouseOver;
		/** Sigal for Mouse-Out event */
		SIG_NOTIFY_EVENT SigMouseOut;
		/** Signal for Mouse-Down event */
		SIG_NOTIFY_EVENT SigMouseDown;
		/** Signal for Mouse-Up event */
		SIG_NOTIFY_EVENT SigMouseUp;
		/** Signal for Mouse-Clicked event */
		SIG_NOTIFY_EVENT SigMouseClicked;

        /** Connection for the Mouse-Over event */
		vector<SIG_CONNECTION> ConnMouseOver;
		/** Connection for the Mouse-Out event */
		vector<SIG_CONNECTION> ConnMouseOut;
		/** Connection for the Mouse-Down event */
		vector<SIG_CONNECTION> ConnMouseDown;
		/** Connection for the Mouse-Up event */
		vector<SIG_CONNECTION> ConnMouseUp;
		/** Connection for the Mouse-Clicked event */
		vector<SIG_CONNECTION> ConnMouseClicked;

        /** Is the widget visible ? */
		bool Visible;
		/** Is it enabled ? */
		bool Enabled;
		/** What's the state of te widget ? \see WIDGET_STATE */
		byte State;
		/** Rectangle of the widget */
		RECTI Rect;
		/** A vector of children */
		std::vector<WIDGET *> Children;

        /**
            @brief An assignment operator
            @param[in] aWidget Reference to the widget to be copied
            @return Reference to the freshly copied widget
        */
		WIDGET& operator= (const WIDGET &aWidget);

        /**
            @brief Sets the Mouse-Over event handler callback function pointer
            @param[in] aNotifyHandler Pointer to the Mouse-Over event handler callback function
            @return The freshly produced connection
        */
        SIG_CONNECTION doOnMouseOver (NOTIFY_HANDLER aNotifyHandler);
        /**
            @brief Sets the Mouse-Out event handler callback function pointer
            @param[in] aNotifyHandler Pointer to the Mouse-Out event handler callback function
            @return The freshly produced connection
        */
        SIG_CONNECTION doOnMouseOut (NOTIFY_HANDLER aNotifyHandler);
        /**
            @brief Sets the Mouse-Down event handler callback function pointer
            @param[in] aNotifyHandler Pointer to the Mouse-Down event handler callback function
            @return The freshly produced connection
        */
        SIG_CONNECTION doOnMouseDown (NOTIFY_HANDLER aNotifyHandler);
        /**
            @brief Sets the Mouse-Up event handler callback function pointer
            @param[in] aNotifyHandler Pointer to the .. (uh, copy the same long text here)
            @return The freshly produced connection
        */
        SIG_CONNECTION doOnMouseUp (NOTIFY_HANDLER aNotifyHandler);
        /**
            @brief Sets the Mouse-Clicked event handler callback function pointer
            @param[in] aNotifyHandler Pointer to the .. (and here aswell)
            @return The freshly produced connection
        */
        SIG_CONNECTION doOnMouseClicked (NOTIFY_HANDLER aNotifyHandler);

        /**
            @brief Recursively shows the widget and its children
        */
		void Show ();
        /**
            @brief Recursively hides the widget and its children
        */
		void Hide ();

        /**
            @brief Recursively enables the widget and its children
        */
        void Enable ();
        /**
            @brief Recursively disables the widget and its children
        */
		void Disable ();

        /**
            @brief Sets the state of the widget
            @param[in] newState The new state to be set
            \see WIDGET_STATE
        */
		void SetState (WIDGET_STATE newState);

        /**
            @brief Fits widget to its children
        */
		void FitChildren ();
        /**
            @brief Expands the widget if its children occupy a larger area than the widget itself
        */
        void ExpandByChildren ();

        /**
            @brief Performs a mousecheck on the widget
            @param[in] Input Pointer to the input class
            @param[in] Check What kind of check should we perform ?
            @return Pointer to the widget (this or its children) that got hit by the mouse.
            NULL if the mouse event missed us completely.
        */
		WIDGET *CheckMouse (INPUT *Input, WIDGET_STATE Check);

        /**
            @brief Moves the widget
            @param[in] aPos Reference to the new position
        */
		void SetPosition (const VEC2I &aPos);

        /**
            @brief Attaches a widget to the children list
            @param[in] widget Pointer to the widget to be attached
        */
		void AttachWidget (WIDGET *widget);

        /**
            @brief Clears the widget and its children
        */
		void Clear ();


        /**
            @brief An abstract function for all widgets
        */
		virtual void Draw (float aElapsedTime = 0.0f) {}

        /**
            @brief Gets the type of the widget
            @return the type index. \see TYPE_MANAGER
        */
		virtual uint GetType () { return MainTypeMgr.GetType ("W_DUMMY"); }

        /**
            @brief Is the widget static ?
            @return The general widget is
        */
		virtual bool IsStatic () { return true; }
};

}
}

#endif
